#ifdef __aarch64__
    .text
    .align  5
    //.p2align 5,,15
    .global Conv14x4
#ifndef __APPLE__
    .type   Conv14x4, %function
#endif

.macro INIT_ZERO
    // we could also use "movi v0.4s, 0" to initialize v0 by 0
    // but let us use less immediate numbers
    // as wzr(w31) is prefined as 0
    // wo do this though it seems not necessarily to initialize register v16 ~ v31
    dup v18.4s, wzr
    dup v19.4s, wzr
    dup v20.4s, wzr
    dup v21.4s, wzr
    dup v22.4s, wzr
    dup v23.4s, wzr
    dup v24.4s, wzr
    dup v25.4s, wzr
    dup v26.4s, wzr
    dup v27.4s, wzr
    dup v28.4s, wzr
    dup v29.4s, wzr
    dup v30.4s, wzr
    dup v31.4s, wzr
.endm

// void Conv14x4(dst, src, weight, src_depth, dst_step, dst_depth, weight_depth);
// x0: dst, x1: src, x2: weight, x3: channel / 4 * ksize, x4: ow*oh*4, x5: oc / 4, x6: 0
Conv14x4:
    // registers v8 ~ v15 must be preserved by a callee across subroutine calls, according to
    // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst#simd-and-floating-point-registers
    sub sp, sp, #128
    // performance between storing 4 registers at the same time and seperatly storing them on in-order cores
    // is not tested yet
    st1 {v8.4s, v9.4s, v10.4s, v11.4s}, [sp], #64
    st1 {v12.4s, v13.4s, v14.4s, v15.4s}, [sp], #64

    // INIT_ZERO

    mov x12, #4 // input
    mul x4, x12, x4
    mul x6, x12, x6

    LoopDz:
        mov x8, x1 
        subs x9, x3, #1
        ld1 {v14.4s, v15.4s, v16.4s, v17.4s}, [x2], #64
        ld1 {v0.4s, v1.4s}, [x8], #32
        fmul v18.4s, v14.4s, v0.s[0]
        ld1 {v2.4s, v3.4s}, [x8], #32
        fmul v19.4s, v14.4s, v1.s[0]
        ld1 {v4.4s, v5.4s, v6.4s, v7.4s}, [x8], #64
        fmul v20.4s, v14.4s, v2.s[0]
        fmul v21.4s, v14.4s, v3.s[0]
        ld1 {v8.4s, v9.4s, v10.4s, v11.4s}, [x8], #64
        fmul v22.4s, v14.4s, v4.s[0]
        fmul v23.4s, v14.4s, v5.s[0]
        ld1 {v12.4s, v13.4s}, [x8], #32
        fmul v24.4s, v14.4s, v6.s[0]
        fmul v25.4s, v14.4s, v7.s[0]
        fmul v26.4s, v14.4s, v8.s[0]
        fmul v27.4s, v14.4s, v9.s[0]
        fmul v28.4s, v14.4s, v10.s[0]
        fmul v29.4s, v14.4s, v11.s[0]
        fmul v30.4s, v14.4s, v12.s[0]
        fmul v31.4s, v14.4s, v13.s[0]

        beq L14LoopZEnd
    
    L14Loopz:
        fmul v18.4s, v15.4s, v0.s[0]
        fmul v19.4s, v15.4s, v1.s[0]
        fmul v20.4s, v15.4s, v2.s[0]
        fmul v21.4s, v15.4s, v3.s[0]
        fmul v22.4s, v15.4s, v4.s[0]
        fmul v23.4s, v15.4s, v5.s[0]
        fmul v24.4s, v15.4s, v6.s[0]
        fmul v25.4s, v15.4s, v7.s[0]
        fmul v26.4s, v15.4s, v8.s[0]
        fmul v27.4s, v15.4s, v9.s[0]
        fmul v28.4s, v15.4s, v10.s[0]
        fmul v29.4s, v15.4s, v11.s[0]
        fmul v30.4s, v15.4s, v12.s[0]
        fmul v31.4s, v15.4s, v13.s[0]

        fmul v18.4s, v16.4s, v0.s[0]
        fmul v19.4s, v16.4s, v1.s[0]
        fmul v20.4s, v16.4s, v2.s[0]
        fmul v21.4s, v16.4s, v3.s[0]
        fmul v22.4s, v16.4s, v4.s[0]
        fmul v23.4s, v16.4s, v5.s[0]
        fmul v24.4s, v16.4s, v6.s[0]
        fmul v25.4s, v16.4s, v7.s[0]
        fmul v26.4s, v16.4s, v8.s[0]
        fmul v27.4s, v16.4s, v9.s[0]
        fmul v28.4s, v16.4s, v10.s[0]
        fmul v29.4s, v16.4s, v11.s[0]
        fmul v30.4s, v16.4s, v12.s[0]
        fmul v31.4s, v16.4s, v13.s[0]

        fmul v18.4s, v17.4s, v0.s[0]
        fmul v19.4s, v17.4s, v1.s[0]
        fmul v20.4s, v17.4s, v2.s[0]
        fmul v21.4s, v17.4s, v3.s[0]
        fmul v22.4s, v17.4s, v4.s[0]
        fmul v23.4s, v17.4s, v5.s[0]
        fmul v24.4s, v17.4s, v6.s[0]
        fmul v25.4s, v17.4s, v7.s[0]
        fmul v26.4s, v17.4s, v8.s[0]
        fmul v27.4s, v17.4s, v9.s[0]
        fmul v28.4s, v17.4s, v10.s[0]
        fmul v29.4s, v17.4s, v11.s[0]
        fmul v30.4s, v17.4s, v12.s[0]
        fmul v31.4s, v17.4s, v13.s[0]

        ld1 {v14.4s, v15.4s, v16.4s, v17.4s}, [x2], #64

        ld1 {v0.4s, v1.4s}, [x8], #32
        fmul v18.4s, v14.4s, v0.s[0]
        ld1 {v2.4s, v3.4s}, [x8], #32
        fmul v19.4s, v14.4s, v1.s[0]
        ld1 {v4.4s, v5.4s, v6.4s, v7.4s}, [x8], #64
        fmul v20.4s, v14.4s, v2.s[0]
        fmul v21.4s, v14.4s, v3.s[0]
        ld1 {v8.4s, v9.4s, v10.4s, v11.4s}, [x8], #64
        fmul v22.4s, v14.4s, v4.s[0]
        fmul v23.4s, v14.4s, v5.s[0]
        ld1 {v12.4s, v13.4s}, [x8], #32
        fmul v24.4s, v14.4s, v6.s[0]
        fmul v25.4s, v14.4s, v7.s[0]
        fmul v26.4s, v14.4s, v8.s[0]
        fmul v27.4s, v14.4s, v9.s[0]
        fmul v28.4s, v14.4s, v10.s[0]
        fmul v29.4s, v14.4s, v11.s[0]
        fmul v30.4s, v14.4s, v12.s[0]
        fmul v31.4s, v14.4s, v13.s[0]

        subs x9, x9, #1
        bne L14Loopz

    L14LoopZEnd:
        fmul v18.4s, v15.4s, v0.s[0]
        fmul v19.4s, v15.4s, v1.s[0]
        fmul v20.4s, v15.4s, v2.s[0]
        fmul v21.4s, v15.4s, v3.s[0]
        fmul v22.4s, v15.4s, v4.s[0]
        fmul v23.4s, v15.4s, v5.s[0]
        fmul v24.4s, v15.4s, v6.s[0]
        fmul v25.4s, v15.4s, v7.s[0]
        fmul v26.4s, v15.4s, v8.s[0]
        fmul v27.4s, v15.4s, v9.s[0]
        fmul v28.4s, v15.4s, v10.s[0]
        fmul v29.4s, v15.4s, v11.s[0]
        fmul v30.4s, v15.4s, v12.s[0]
        fmul v31.4s, v15.4s, v13.s[0]

        fmul v18.4s, v16.4s, v0.s[0]
        fmul v19.4s, v16.4s, v1.s[0]
        fmul v20.4s, v16.4s, v2.s[0]
        fmul v21.4s, v16.4s, v3.s[0]
        fmul v22.4s, v16.4s, v4.s[0]
        fmul v23.4s, v16.4s, v5.s[0]
        fmul v24.4s, v16.4s, v6.s[0]
        fmul v25.4s, v16.4s, v7.s[0]
        fmul v26.4s, v16.4s, v8.s[0]
        fmul v27.4s, v16.4s, v9.s[0]
        fmul v28.4s, v16.4s, v10.s[0]
        fmul v29.4s, v16.4s, v11.s[0]
        fmul v30.4s, v16.4s, v12.s[0]
        fmul v31.4s, v16.4s, v13.s[0]

        mov x12, x0

        fmul v18.4s, v17.4s, v0.s[0]
        fmul v19.4s, v17.4s, v1.s[0]
        fmul v20.4s, v17.4s, v2.s[0]
        fmul v21.4s, v17.4s, v3.s[0]
        fmul v22.4s, v17.4s, v4.s[0]
        st1 {v18.4s, v19.4s}, [x0], #32
        fmul v23.4s, v17.4s, v5.s[0]
        fmul v24.4s, v17.4s, v6.s[0]
        fmul v25.4s, v17.4s, v7.s[0]
        fmul v26.4s, v17.4s, v8.s[0]
        st1 {v20.4s, v21.4s, v22.4s, v23.4s}, [x0], #64
        fmul v27.4s, v17.4s, v9.s[0]
        fmul v28.4s, v17.4s, v10.s[0]
        fmul v29.4s, v17.4s, v11.s[0]
        fmul v30.4s, v17.4s, v12.s[0]
        st1 {v24.4s, v25.4s, v26.4s, v27.4s}, [x0], #64
        fmul v31.4s, v17.4s, v13.s[0]
        add x2, x2, x6

        st1 {v28.4s, v29.4s, v30.4s, v31.4s}, [x0], #64

        subs x5, x5, #1
        add x0, x12, x4

        bne LoopDz

    sub sp, sp, #128
    ld1 {v8.4s, v9.4s, v10.4s, v11.4s}, [sp], #64
    ld1 {v12.4s, v13.4s, v14.4s, v15.4s}, [sp], #64
    ret
#endif
